﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Resources;
using System.Linq;

namespace WPHttpServer
{
    public class ResourceManager
    {
        public string BasePath { get; set; }

        #region Fileextention - MIME-Type mapping
        private readonly Dictionary<string, string> _fileExtentionMimeMapping = new Dictionary<string, string>()
        {
            {".html", "text/html"},
            {".css", "text/css"},
            {".js", "text/javascript"}


            //{".dwg", "application/acad"},
            //{".asd", "application/astound"},
            //{".tsp", "application/dsptype"},
            //{".dxf", "application/dxf"},
            //{".spl", "application/futuresplash"},
            //{".gz", "application/gzip"},
            //{".ptlk", "application/listenup"},
            //{".hqx", "application/mac-binhex40"},
            //{".mbd", "application/mbedlet"},
            //{".mif", "application/mif"},
            //{".xls", "application/msexcel"},
            //{".hlp", "application/mshelp"},
            //{".ppt", "application/mspowerpoint"},
            //{".doc", "application/msword"},
            //{".bin", "application/octet-stream"},
            //{".oda", "application/oda"},
            //{".pdf", "application/pdf"},
            //{".ai", "application/postscript"},
            //{".rtc", "application/rtc"},
            //{".rtf", "application/rtf"},
            //{".smp", "application/studiom"},
            //{".tbk", "application/toolbook"},
            //{".vmd", "application/vocaltec-media-desc"},
            //{".vmf", "application/vocaltec-media-file"},
            //{".htm", "application/xhtml+xml"},
            //{".xml", "application/xml"},
            //{".bcpio", "application/x-bcpio"},
            //{".z", "application/x-compress"},
            //{".cpio", "application/x-cpio"},
            //{".csh", "application/x-csh"},
            //{".dcr", "application/x-director"},
            //{".dvi", "application/x-dvi"},
            //{".evy", "application/x-envoy"},
            //{".gtar", "application/x-gtar"},
            //{".hdf", "application/x-hdf"},
            //{".php", "application/x-httpd-php"},
            //{".js", "application/x-javascript"},
            //{".latex", "application/x-latex"},
            //{".bin", "application/x-macbinary"},
            //{".mif", "application/x-mif"},
            //{".nc", "application/x-netcdf"},
            //{".nsc", "application/x-nschat"},
            //{".sh", "application/x-sh"},
            //{".shar", "application/x-shar"},
            //{".swf", "application/x-shockwave-flash"},
            //{".spr", "application/x-sprite"},
            //{".sit", "application/x-stuffit"},
            //{".sca", "application/x-supercard"},
            //{".sv4cpio", "application/x-sv4cpio"},
            //{".sv4crc", "application/x-sv4crc"},
            //{".tar", "application/x-tar"},
            //{".tcl", "application/x-tcl"},
            //{".tex", "application/x-tex"},
            //{".texinfo", "application/x-texinfo"},
            //{".t", "application/x-troff"},
            //{".man", "application/x-troff-man"},
            //{".me", "application/x-troff-me"},
            //{".me", "application/x-troff-ms"},
            //{".ustar", "application/x-ustar"},
            //{".src", "application/x-wais-source"},
            //{".zip", "application/zip"},
            //{".au", "audio/basic"},
            //{".es", "audio/echospeech"},
            //{".tsi", "audio/tsplayer"},
            //{".vox", "audio/voxware"},
            //{".aif", "audio/x-aiff"},
            //{".dus", "audio/x-dspeeh"},
            //{".mid", "audio/x-midi"},
            //{".mp2", "audio/x-mpeg"},
            //{".ram", "audio/x-pn-realaudio"},
            //{".rpm", "audio/x-pn-realaudio-plugin"},
            //{".stream", "audio/x-qt-stream"},
            //{".wav", "audio/x-wav"},
            //{".dwf", "drawing/x-dwf"},
            //{".cod", "image/cis-cod"},
            //{".ras", "image/cmu-raster"},
            //{".fif", "image/fif"},
            //{".gif", "image/gif"},
            //{".ief", "image/ief"},
            //{".jpeg", "image/jpeg"},
            //{".png", "image/png"},
            //{".tiff", "image/tiff"},
            //{".mcf", "image/vasa"},
            //{".wbmp", "image/vnd.wap.wbmp"},
            //{".fh4", "image/x-freehand"},
            //{".ico", "image/x-icon"},
            //{".pnm", "image/x-portable-anymap"},
            //{".pbm", "image/x-portable-bitmap"},
            //{".pgm", "image/x-portable-graymap"},
            //{".ppm", "image/x-portable-pixmap"},
            //{".rgb", "image/x-rgb"},
            //{".xwd", "image/x-windowdump"},
            //{".xbm", "image/x-xbitmap"},
            //{".xpm", "image/x-xpixmap"},
            //{".wrl", "model/vrml"},
            //{".csv", "text/comma-separated-values"},
            //{".css", "text/css"},
            //{".htm", "text/html"},
            //{".js", "text/javascript"},
            //{".txt", "text/plain"},
            //{".rtx", "text/richtext"},
            //{".rtf", "text/rtf"},
            //{".tsv", "text/tab-separated-values"},
            //{".wml", "text/vnd.wap.wml"},
            //{".wmlc", "application/vnd.wap.wmlc"},
            //{".wmls", "text/vnd.wap.wmlscript"},
            //{".wmlsc", "application/vnd.wap.wmlscriptc"},
            //{".xml", "text/xml"},
            //{".etx", "text/x-setext"},
            //{".sgm", "text/x-sgml"},
            //{".talk", "text/x-speech"},
            //{".mpeg", "video/mpeg"},
            //{".qt", "video/quicktime"},
            //{".viv", "video/vnd.vivo"},
            //{".avi", "video/x-msvideo"},
            //{".movie", "video/x-sgi-movie"},
            //{".vts", "workbook/formulaone"},
            //{".3dmf", "x-world/x-3dmf"},
            //{".wrl", "x-world/x-vrml"},
        }; 
        #endregion

        /// <summary>
        /// Key -> external path
        /// Value -> content provider
        /// </summary>
        private readonly Dictionary<string, DynamicResponseContentProvider> _cachedResources;

        private readonly Dictionary<string, string> _registeredResources;

        public ResourceManager(string internalBasePath)
        {
            this.BasePath = internalBasePath;
            this._cachedResources = new Dictionary<string, DynamicResponseContentProvider>();
            this._registeredResources = new Dictionary<string, string>();
        }

        public void RegisterResource(string internalPath, string externalPath)
        {
            if (!externalPath.StartsWith("/"))
            {
                throw new ArgumentOutOfRangeException("externalPath", "External pathes must start with an leading \"/\"");
            }

            if (internalPath.StartsWith("/"))
            {
                throw new ArgumentOutOfRangeException("internalPath", "Internal pathes must **not** start with an leading \"/\"");
            }

            this._registeredResources.Add(externalPath, internalPath);
        }

        public void RegisterResource(string universalPath)
        {
            // internal pathes do not start with leading /
            string internalPath = universalPath.Substring(1, universalPath.Length - 1);

            // external do
            string externalPath = universalPath;

            RegisterResource(internalPath, externalPath);
        }

        internal HttpRequestHandler GetContentAtUri(string externalPath)
        {
            DynamicResponseContentProvider contentProvider;

            if (this._cachedResources.ContainsKey(externalPath))
            {
                contentProvider = this._cachedResources[externalPath];
            }
            else
            {
                // if not found return null --> 404 not found
                if (!this._registeredResources.ContainsKey(externalPath))
                {
                    return null;
                }

                string internalPath = this.BasePath + "/" + this._registeredResources[externalPath];

                StreamResourceInfo resourceInfo = Application.GetResourceStream(new Uri(internalPath, UriKind.Relative));

                if (resourceInfo == null)
                {
                    return null;
                }

                byte[] buffer = new byte[resourceInfo.Stream.Length];
                resourceInfo.Stream.Read(buffer, 0, buffer.Length);

                string contentType;

                if (string.IsNullOrWhiteSpace(resourceInfo.ContentType))
                {
                    contentType = this.LookupContentType(Path.GetExtension(internalPath));
                }
                else
                {
                    contentType = resourceInfo.ContentType;
                }

                contentProvider = new DynamicResponseContentProvider(buffer, contentType);

                // cache it, it's static content!
                this._cachedResources.Add(externalPath, contentProvider);
            }

            return request =>
            {
                return new HttpResponse(HttpStatusCode.Ok)
                {
                    Content = contentProvider
                };
            };
        }

        private string LookupContentType(string fileExtention)
        {
            fileExtention = fileExtention.ToLower();

            if (_fileExtentionMimeMapping.ContainsKey(fileExtention))
            {
                return _fileExtentionMimeMapping[fileExtention];
            }
            else
            {
                return null;
            }
        }
    }
}